home *** CD-ROM | disk | FTP | other *** search
/ Netscape Plug-Ins Developer's Kit / Netscape_Plug-Ins_Developers_Kit.iso / CGIPERL / MACPERL / MSRCE418.HQX / Perl Source ƒ / Perl / icemalloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-01  |  35.2 KB  |  1,455 lines

  1.  
  2. /*
  3. **
  4. ** Notice.
  5. **
  6. ** This source code was written by Tim Endres. time@ice.com
  7. ** Copyright 1988-1991 ⌐ By Tim Endres. All rights reserved.
  8. ** 8840 Main Street, Whitmore Lake, MI  48189
  9. **
  10. ** You may use this source code for any purpose you can dream
  11. ** of as long as this notice is never modified nor removed.
  12. **
  13. ** Please email me any improvements that you might make. Any
  14. ** reasonable form of diff (compare) on the files changes will
  15. ** do nicely. You can mail "time@ice.com". Thank you.
  16. **
  17. ** BTW: In case it is not obvious, do not #define DOCUMENTATION ;)
  18. **
  19. * $Log: icemalloc.c,v $
  20.  * Revision 1.3  1994/05/04  02:10:46  neeri
  21.  * Rewrote memory management.
  22.  *
  23.  * Revision 1.2  1994/04/01  17:51:22  neeri
  24.  * Bucket allocator works.
  25.  *
  26. */
  27.  
  28.  
  29. #include <types.h>
  30. #include <memory.h>
  31.  
  32. #include "icemalloc.h"
  33.  
  34. #define mNEWPTR(size)            ( NewPtr ( (size) ) )
  35. #define mDISPOSPTR(ptr)            ( DisposPtr ( (ptr) ) )
  36.  
  37. #define DEBUG
  38.  
  39. #if !defined(powerc) && !defined(__powerc)
  40. #define ice_malloc     malloc
  41. #define ice_free        free
  42. #define ice_realloc    realloc
  43. #define ice_calloc    calloc
  44. #endif
  45.  
  46. #ifdef DOCUMENTATION
  47.  
  48.     malloc() will allocate "size" bytes from the default malloc pool.
  49.     
  50. #endif
  51.  
  52. char    *
  53. ice_malloc ( size )
  54. u_long    size;
  55. {
  56. _mem_pool_ptr    pool;
  57.  
  58.     pool = _default_mem_pool;
  59.     if (pool == (_mem_pool_ptr)0)
  60.         return (char *)0;
  61.     
  62.     return _pool_malloc(pool, size);
  63.     }
  64.  
  65.  
  66. #ifdef DOCUMENTATION
  67.  
  68.     free() will free the memory occupied by the "ptr" allocated by malloc().
  69.     
  70. #endif
  71.  
  72. void ice_free ( void * ptr )
  73. {
  74.     _pool_free((char *) ptr);
  75.     }
  76.  
  77. #ifdef DOCUMENTATION
  78.  
  79.     MN 15May93 realloc() tries to change the size of the memory pointed 
  80.     to by "ptr". No optimizations are attempted.
  81.     
  82. #endif
  83.  
  84. void *
  85. ice_realloc ( old, size )
  86. void *     old;
  87. u_long    size;
  88. {
  89.     void *            nu;
  90.     
  91.     nu = ice_malloc(size);
  92.     
  93.     if (!old || !nu)
  94.         return nu;
  95.     
  96.     memcpy(nu, old, size);
  97.     
  98.     ice_free(old);
  99.     
  100.     return nu;
  101. }
  102.  
  103.  
  104. #ifdef DOCUMENTATION
  105.  
  106.     MN 27Jul94 calloc() tries to change the size of the memory pointed 
  107.     to by "ptr". No optimizations are attempted.
  108.     
  109. #endif
  110.  
  111. void *
  112. ice_calloc (nmemb, size)
  113. u_long     nmemb;
  114. u_long    size;
  115. {
  116.     return ice_malloc(nmemb*size);
  117. }
  118.  
  119.  
  120. void
  121. fastzero(ptr, size)
  122. register char *ptr;
  123. register u_long size;
  124. {
  125.     int     portiuncula;
  126.     int     longs;
  127.     int     max;
  128.     long    *lptr;
  129.  
  130.     longs = size >> 2;
  131.     lptr  = (long *) ptr;
  132.     max   = 8;
  133.     
  134.     switch (longs) {
  135.     default:
  136.         *lptr++ = 0;
  137.     case 7:
  138.         *lptr++ = 0;
  139.     case 6:
  140.         *lptr++ = 0;
  141.     case 5:
  142.         *lptr++ = 0;
  143.     case 4:
  144.         *lptr++ = 0;
  145.     case 3:
  146.         *lptr++ = 0;
  147.     case 2:
  148.         *lptr++ = 0;
  149.     case 1:
  150.         *lptr++ = 0;
  151.     case 0:
  152.         break;
  153.     }
  154.     
  155.     for (longs -= 8; longs > 0; longs -= portiuncula) {
  156.         portiuncula = longs > max ? max : longs;
  157.         BlockMove((Ptr)(lptr - portiuncula), (Ptr) lptr, portiuncula*4);
  158.         max += portiuncula;
  159.         lptr += portiuncula;
  160.     }
  161. }
  162.  
  163. #ifdef DOCUMENTATION
  164.  
  165.     set_default_pool() - given a pool id, this routine will make it the default
  166.     pool from which malloc() allocates memory.
  167.     
  168. #endif
  169.  
  170.  
  171. int set_default_pool ( id )
  172. int        id;
  173. {
  174. _mem_pool_ptr    pool, last;
  175.  
  176.     if (_default_mem_pool->id == id)
  177.         return 0;
  178.     
  179.     last = _default_mem_pool;
  180.     pool = _default_mem_pool->next;
  181.     for ( ; pool != (_mem_pool_ptr)0 ; pool = pool->next) {
  182.         if (pool->id == id) {
  183.             last->next = pool->next;
  184.             pool->next = _default_mem_pool;
  185.             _default_mem_pool = pool;
  186.             return 0;
  187.             }
  188.         }
  189.     
  190.     return -1;
  191.     }
  192.  
  193.  
  194. #ifdef DOCUMENTATION
  195.  
  196.     new_malloc_pool() creates a new pool from which memory can be malloc()-ed.
  197.     
  198. #endif
  199.  
  200. _mem_pool_ptr
  201. new_malloc_pool ( id, pref_blk_size )
  202. int        id;
  203. u_long    pref_blk_size;
  204. {
  205. _mem_pool_ptr    new_pool;
  206.  
  207.     new_pool = find_pool(id);
  208.     if (new_pool != NULL)            /* ? Is this the best choice? Its not ID-able */
  209.         return new_pool;
  210.  
  211.     new_pool = (_mem_pool_ptr) mNEWPTR( sizeof(_mem_pool) );
  212.     if (new_pool == (_mem_pool_ptr)0)
  213.         return new_pool;
  214.     
  215.     new_pool->id = id;                            /* The pool's ID. */
  216.     new_pool->pref_blk_size = pref_blk_size;    /* The preferred size of new blks. */
  217.     new_pool->blk_list = NULL;                    /* The list of blocks in the pool. */
  218.     new_pool->blk_16 = nil;
  219.     new_pool->blk_32 = nil;
  220.     new_pool->blk_64 = nil;
  221.     new_pool->free_16 = nil;
  222.     new_pool->free_32 = nil;
  223.     new_pool->free_64 = nil;
  224.     
  225.     /* The next two lines insert right after the default, so we don't change it. */
  226.     new_pool->next = _mem_pool_forest->next;
  227.     _mem_pool_forest->next = new_pool;
  228.  
  229. #ifdef _PM_STATS
  230.     new_pool->total_memory = 0;            /* The total allocated memory by this pool */
  231.     new_pool->total_storage = 0;        /* The total malloc-able storage in this pool */
  232.     new_pool->total_malloc = 0;            /* The total malloc-ed storage not freed. */
  233.     new_pool->max_blk_size = 0;            /* The maximum block size allocated. */
  234.     new_pool->ave_req_size = 0.0;        /* The ave allocated request size */
  235.     new_pool->ave_req_total = 0;        /* The total requests in the average. */
  236.     new_pool->ave_blk_size = 0.0;        /* The ave sallocated blk size */
  237.     new_pool->ave_blk_total = 0;        /* The total blks in the average. */
  238. #endif
  239.  
  240.     return new_pool;
  241.     }
  242.  
  243.  
  244. #ifdef DOCUMENTATION
  245.  
  246.     find_pool() will find the pool with the given "id" and return its pointer.
  247.     
  248. #endif
  249.  
  250. _mem_pool_ptr
  251. find_pool ( id )
  252. int        id;
  253. {
  254. _mem_pool_ptr    pool;
  255.  
  256.     for (pool = _mem_pool_forest ; pool != (_mem_pool_ptr)0 ; pool = pool->next) {
  257.         if (pool->id == id)
  258.             break;
  259.         }
  260.         
  261.     return pool;
  262.     }
  263.  
  264.  
  265. #ifdef DOCUMENTATION
  266.  
  267.     free_pool_memory() this will free and *release* all memory occupied by the
  268.     pool but not free the pool, letting you allocate some more.
  269.     
  270. #endif
  271.  
  272. free_pool_memory ( id )
  273. int        id;
  274. {
  275. _mem_pool_ptr        pool;
  276. _mem_blk_ptr        blk, nextblk;
  277. _mem_bucket_ptr    bucket;
  278.  
  279.     pool = find_pool(id);
  280.     if (pool == NULL)
  281.         return -1;
  282.     
  283.     /* The buckets themselves are always allocated from the pool and therefore
  284.        don't need to be disposed explicitely.
  285.     */
  286.     
  287.     for ( bucket = pool->blk_16; bucket; bucket = bucket->next)
  288.         mDISPOSPTR((Ptr) bucket->memory);
  289.     for ( bucket = pool->blk_32; bucket; bucket = bucket->next)
  290.         mDISPOSPTR((Ptr) bucket->memory);
  291.     for ( bucket = pool->blk_64; bucket; bucket = bucket->next)
  292.         mDISPOSPTR((Ptr) bucket->memory);
  293.     
  294.     pool->blk_16 = nil;
  295.     pool->blk_32 = nil;
  296.     pool->blk_64 = nil;
  297.     pool->free_16 = nil;
  298.     pool->free_32 = nil;
  299.     pool->free_64 = nil;
  300.     
  301.     for ( blk = pool->blk_list ; blk != (_mem_blk_ptr)0 ; ) {
  302.         nextblk = blk->next;
  303.         DPRINTF(3, ("pool_find_free_blk() Freeing Block x%lx from pool #%d!\n",
  304.                         blk, blk->pool->id));
  305. #ifdef _PM_STATS
  306.         pool->total_memory -= sizeof(_mem_blk) + blk->size;
  307.         pool->total_storage -= blk->size;
  308. #endif
  309.         mDISPOSPTR((Ptr)blk->memory);
  310.         mDISPOSPTR((Ptr)blk);
  311.  
  312.         blk = nextblk;
  313.         }
  314.  
  315.     pool->blk_list = NULL;
  316.     
  317.     return 0;
  318.     }
  319.  
  320.  
  321. #ifdef DOCUMENTATION
  322.  
  323.     free_pool() will free the pool's memory *and* free the pool (removing
  324.     it from the pool list) releasing all memory back to the heap.
  325.     
  326. #endif
  327.  
  328. free_pool ( id )
  329. int        id;
  330. {
  331. _mem_pool_ptr    pool;
  332.  
  333.     if (free_pool_memory(id) == -1)
  334.         return -1;
  335.     
  336.     pool = find_pool(id);
  337.     if (pool == NULL)
  338.         return -1;
  339.     
  340.     mDISPOSPTR((Ptr)pool);
  341.     
  342.     return 0;
  343.     }
  344.  
  345.  
  346. #ifdef DOCUMENTATION
  347.  
  348.     _pool_malloc() does the low level malloc() work in a specified pool.
  349.     
  350. #endif
  351.  
  352. char * _bucket_malloc();
  353. char * _blk_malloc();
  354.  
  355. char    *
  356. _pool_malloc(pool, size)
  357. _mem_pool_ptr    pool;
  358. u_long            size;
  359. {
  360.     if (size < 33)
  361.         if (size < 17)
  362.             return _bucket_malloc(pool, 16, &pool->free_16, &pool->blk_16, 4);
  363.         else
  364.             return _bucket_malloc(pool, 32, &pool->free_32, &pool->blk_32, 5);
  365.     else 
  366.         if (size < 65)
  367.             return _bucket_malloc(pool, 64, &pool->free_64, &pool->blk_64, 6);
  368.         else
  369.             return _blk_malloc(pool, size);
  370. }
  371.  
  372. char     *
  373. _bucket_malloc(pool, size, free, buckets, shift)
  374. _mem_pool_ptr        pool;
  375. u_long                 size;
  376. _mem_bucket_ptr *    free;
  377. _mem_bucket_ptr *    buckets;
  378. short                    shift;
  379. {
  380.     _mem_bucket_ptr    bucket;
  381.     char *                 mem;
  382.     
  383.     if (!(bucket = *free)) {
  384.         for (bucket = *buckets; bucket && !bucket->free_count; bucket = bucket->next);
  385.     
  386.         if (!bucket) {
  387.             int count;
  388.             int max                = pool->pref_blk_size >> shift;
  389.             char * next;
  390.             
  391.             bucket                = (_mem_bucket_ptr) _blk_malloc(pool, sizeof(_mem_bucket));
  392.             bucket->prev        = (_mem_bucket_ptr) buckets;
  393.             bucket->next         = *buckets;
  394.             *buckets             = bucket;
  395.             bucket->pool         = pool;
  396.             bucket->memory     = mem = mNEWPTR(pool->pref_blk_size);
  397.             bucket->max_count    = max;
  398.             bucket->free_count= max;
  399.             
  400.             *(char **) mem = nil;
  401.             for (count = 1; count++ < max; mem = next) {
  402.                 next = mem + size;
  403.                 *(char **) next = mem;
  404.             }
  405.             bucket->free        = next;
  406.         }
  407.         *free = bucket;
  408.     }
  409.     mem                 = bucket->free;
  410.     bucket->free     = *(char **) mem;
  411.     if (!--bucket->free_count)
  412.         *free = nil;
  413.     else if (bucket->free < bucket->memory || bucket->free > bucket->memory + pool->pref_blk_size)
  414.         DebugStr((StringPtr) "\pFatal allocation error!");
  415.  
  416.     fastzero(mem, size);
  417.     
  418.     return mem;
  419. }
  420.  
  421. char    *
  422. _blk_malloc(pool, size)
  423. _mem_pool_ptr    pool;
  424. u_long            size;
  425. {
  426. _mem_blk_ptr        blk;
  427. _mem_ptr_hdr_ptr    hdr = (_mem_ptr_hdr_ptr)0, freehdr;
  428. u_long                freesize, size_req;
  429. char                *ptr = (char *)0;
  430.  
  431.     DPRINTF(5, ("_pool_malloc() request of %ld bytes in pool #%d [x%lx]\n",
  432.                 size, pool->id, pool));
  433.         
  434.     size_req = (size < _PM_MIN_ALLOC_SIZE) ? _PM_MIN_ALLOC_SIZE : size;
  435.     size_req = INT_ALIGN(size_req, ALIGNMENT);
  436.  
  437. #ifdef _PM_STATS
  438.     pool->ave_req_size = ( ( (pool->ave_req_size * (float)pool->ave_req_total) + (float)size_req )
  439.                             / (float)(pool->ave_req_total + 1) );
  440.     pool->ave_req_total++;
  441. #endif
  442.  
  443.     blk = pool->blk_list;
  444.     if (blk == NULL) {
  445.         /* No blocks in pool, allocate one... */
  446.         blk = _pool_new_blk(pool, size_req);
  447.         }
  448.     else {
  449.         blk = _pool_find_free_blk(pool, size_req, &hdr);
  450.  
  451.         if (blk == (_mem_blk_ptr)0 || hdr == (_mem_ptr_hdr_ptr)0) {
  452.             /* No blocks that can support this size... */
  453.             blk = _pool_new_blk(pool, size_req);
  454.             }
  455.         else
  456.             DPRINTF(5, ("_pool_malloc() found free: blk x%lx hdr x%lx\n",
  457.                         blk, hdr));
  458.         }
  459.     
  460.     if (blk != (_mem_blk_ptr)0) {
  461.         /* Determine the pointer's location, establish, return. */
  462.         if (hdr == (_mem_ptr_hdr_ptr)0) {
  463.             hdr = (_mem_ptr_hdr_ptr) blk->memory;
  464.             DPRINTF(5, ("_pool_malloc() header of new blk blk->memory x%lx\n", blk->memory));
  465.             }
  466.         
  467.         DPRINTF(5, ("_pool_malloc() free hdr x%lx size %ld\n", hdr, GET_PTR_SIZE(hdr)));
  468.         if (hdr != (_mem_ptr_hdr_ptr)0) {
  469.             ptr = (char *)hdr + sizeof(_mem_ptr_hdr);
  470.             
  471.             if (size_req < GET_PTR_SIZE(hdr)) {
  472.                 /* Split this free block... */
  473.                 DPRINTF(5, ("_pool_malloc() split hdr x%lx into %ld used and %ld free\n",
  474.                             hdr, size_req, GET_PTR_SIZE(hdr) - (size_req + sizeof(_mem_ptr_hdr))));
  475.  
  476.                 freehdr = (_mem_ptr_hdr_ptr)
  477.                             ( (char *)hdr + sizeof(_mem_ptr_hdr) + size_req );
  478.                 freesize = GET_PTR_SIZE(hdr) - (sizeof(_mem_ptr_hdr) + size_req);
  479.                 fastzero(freehdr, sizeof(_mem_ptr_hdr));
  480.                 SET_PTR_FREE(freehdr);
  481.                 SET_PTR_SIZE(freehdr, freesize);
  482.                 blk->max_free -= sizeof(_mem_ptr_hdr);
  483.                 }
  484.  
  485. #ifdef _PM_STATS    
  486.             pool->total_malloc += size_req;
  487. #endif
  488.  
  489.             blk->max_free -= size_req;
  490.             SET_PTR_USED(hdr);
  491.             SET_PTR_SIZE(hdr, size_req);
  492.             fastzero(ptr, size_req);        /* Programmer's expect malloc() to zero. */
  493.             }
  494.         else {
  495.             /* ERROR: This should not happen!!! */
  496.             DPRINTF(1, ("ERROR: pool_malloc() could not get block's free hdr ptr\n"));
  497.             DACTION(2, { list_pool_forest(NULL); });
  498.             }
  499.         }
  500.     else {
  501.         /* ERROR, no block, no memory. */
  502.         DPRINTF(1, ("ERROR: pool_malloc() could not get a block\n"));
  503.         DACTION(2, { list_pool_forest(NULL); });
  504.         }
  505.     
  506.     DPRINTF(5, ("_pool_malloc() returning ptr x%lx\n", ptr));
  507.     return ptr;
  508.     }
  509.  
  510. #ifdef DOCUMENTATION
  511.  
  512.     _pool_free() does the low level work of a free().
  513.     
  514. #endif
  515.  
  516. _mem_bucket_ptr _pool_find_ptr_bucket();
  517.  
  518. _pool_free ( ptr )
  519. char    *ptr;
  520. {
  521. _mem_pool_ptr        pool;
  522. _mem_blk_ptr        blk;
  523. _mem_ptr_hdr_ptr    hdr, adjhdr, limit;
  524. int                    result = 0;
  525. u_long                ptr_size, new_size;
  526. _mem_bucket_ptr    bucket;
  527.  
  528.     if (ptr == (char *)0) {
  529.         /* WHOAH! NULL Pointers... */
  530.         DPRINTF(1, ("_pool_free() ptr NULL!"));
  531.         return -1;
  532.         }
  533.     
  534.     if ( ( (u_long)ptr & 1 ) != 0 ) {
  535.         /* WHOAH! ODD Pointers... */
  536.         DPRINTF(1, ("_pool_free() ptr ODD!"));
  537.         return -1;
  538.         }
  539.     
  540.     DPRINTF(5, ("_pool_free() free ptr x%lx\n", ptr));
  541.  
  542.     if (bucket = _pool_find_ptr_bucket(ptr)) {
  543.         if (
  544.             ++bucket->free_count == bucket->max_count
  545.         ) {    /* Kick the bucket */
  546.             bucket->prev->next = bucket->next;
  547.             
  548.             if (bucket->next)
  549.                 bucket->next->prev = bucket->prev;
  550.             
  551.             mDISPOSPTR(bucket->memory);
  552.             _pool_free(bucket);
  553.         } else {
  554.             *(char **) ptr = bucket->free;
  555.             bucket->free = ptr;
  556.         }
  557.         return -1;
  558.     }
  559.         
  560.     blk = _pool_find_ptr_blk(ptr);
  561.     
  562.     if (blk == (_mem_blk_ptr)0) {
  563.         /* We could not find this thing's blk! BUG!!! */
  564.         DPRINTF(1, ("ERROR: free(x%lx) could not find ptr's blk\n", ptr));
  565.         DACTION(2, { list_pool_forest(NULL); });
  566.         result = -1;
  567.         }
  568.     else {
  569.         /*
  570.         ** Now, if it is adjacent to free memory, combine.
  571.         ** NOTE: We only do this because it is SO DAMN CHEAP!!!!!
  572.         */
  573.  
  574.         /* Delay these assigns til we know ptr is good. (now) */
  575.         hdr = (_mem_ptr_hdr_ptr) ( (u_long)ptr - sizeof(_mem_ptr_hdr) );
  576.         ptr_size = GET_PTR_SIZE(hdr);
  577.  
  578.         DPRINTF(5, ("_pool_free() free hdr x%lx size %ld flags x%02x in blk x%lx\n",
  579.                     hdr, ptr_size, GET_PTR_FLAGS(hdr), blk));
  580.     
  581.         pool = blk->pool;
  582.         SET_PTR_FREE(hdr);
  583.         blk->max_free += ptr_size;
  584.         
  585.         adjhdr = (_mem_ptr_hdr_ptr)
  586.                     ( (char *)hdr + GET_PTR_SIZE(hdr) +
  587.                       sizeof(_mem_ptr_hdr) );
  588.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  589.         
  590.         if (adjhdr < limit && IS_PTR_FREE(adjhdr)) {
  591.             DPRINTF(5, ("_pool_free() merging hdr x%lx with freehdr x%lx\n", hdr, adjhdr));
  592.             
  593.             new_size =    GET_PTR_SIZE(hdr) +
  594.                         GET_PTR_SIZE(adjhdr) +
  595.                         sizeof(_mem_ptr_hdr);
  596.  
  597.             DPRINTF(5, ("_pool_free() merged hdr new_size %ld\n", new_size));
  598.             SET_PTR_SIZE(hdr, new_size);
  599.             blk->max_free += sizeof(_mem_ptr_hdr);
  600.             }    /* is adjacent free ? */
  601.         
  602. #ifdef _PM_STATS    
  603.         pool->total_malloc -= ptr_size;
  604. #endif
  605.  
  606. #ifdef _PM_DYNAMIC_FREE
  607.         if (block_is_freed(blk)) {
  608.             /* This blk is free-ed ... */
  609.             _mem_blk_ptr    tmpblk;
  610.  
  611.             if (blk == blk->pool->blk_list) {
  612.                 blk->pool->blk_list = blk->next;
  613.                 }
  614.             else {
  615.                 tmpblk = blk->pool->blk_list;
  616.                 while (tmpblk != (_mem_blk_ptr)0) {
  617.                     if (tmpblk->next == blk) {
  618.                         tmpblk->next = blk->next;
  619.                         break;
  620.                         }
  621.                     else
  622.                         tmpblk = tmpblk->next;
  623.                     }
  624.                 if (tmpblk == (_mem_blk_ptr)0)
  625.                     DPRINTF(1, ("ERROR: could not free blk x%lx from list!\n", blk));
  626.                 }
  627.             
  628.             DPRINTF(3, ("_pool_free() Freeing Block x%lx from pool #%d!\n",
  629.                         blk, blk->pool->id));
  630. #ifdef _PM_STATS
  631.             pool->total_memory -= sizeof(_mem_blk) + blk->size;
  632.             pool->total_storage -= blk->size;
  633. #endif
  634.             mDISPOSPTR((Ptr)blk->memory);
  635.             mDISPOSPTR((Ptr)blk);
  636.             }    /* if (block_is_freed(blk)) */
  637. #endif _PM_DYNAMIC_FREE
  638.  
  639.         result = 0;
  640.         }    /* else we found the block containing the ptr. */
  641.     
  642.     return result;
  643.     }
  644.  
  645. #ifdef DOCUMENTATION
  646.  
  647.     block_is_freed() determines if all memory in a given block is free.
  648.     
  649. #endif
  650.  
  651. block_is_freed(blk)
  652. _mem_blk_ptr    blk;
  653. {
  654. int            freed = 1;
  655. _mem_ptr_hdr_ptr    loophdr, limit;
  656.  
  657. /*
  658. ** This loop is not as expensive as you might think, since most of the
  659. ** time we've "merged" into few "ptrs", and in allocated cases we will
  660. ** break out of the loop almost immediately.
  661. */
  662.  
  663.     if (blk != NULL) {
  664.         loophdr = (_mem_ptr_hdr_ptr) blk->memory;
  665.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  666.         while (loophdr < limit) {
  667.             if (! IS_PTR_FREE(loophdr)) {
  668.                 freed = 0;
  669.                 break;
  670.                 }
  671.             
  672.             loophdr = (_mem_ptr_hdr_ptr)
  673.                         ((char *)loophdr + GET_PTR_SIZE(loophdr) + sizeof(_mem_ptr_hdr));
  674.             }
  675.         }
  676.     else
  677.         freed = 0;    /* ? Or is it really free? */
  678.     
  679.     return freed;
  680.     }
  681.  
  682.  
  683. #ifdef DOCUMENTATION
  684.  
  685.     _pool_new_blk() allocate a new memory block to a pool. This is called
  686.     by the low level malloc() code when new memory is needed.
  687.     
  688. #endif
  689.  
  690. _mem_blk_ptr
  691. _pool_new_blk(pool, size_req)
  692. _mem_pool_ptr    pool;
  693. u_long            size_req;    /* size required */
  694. {
  695. u_long                blk_size;
  696. _mem_blk_ptr        new_blk;
  697. _mem_ptr_hdr_ptr    hdr;
  698.  
  699.     DPRINTF(5, ("_pool_new_blk() req_size %ld pool #%d [x%lx]\n", size_req, pool->id, pool));
  700.  
  701.     /* MN 29Mar94 To avoid agonizing death from internal fragmentation, we make an 
  702.        allocation "private" if it would occupy more than about 45% of a block.
  703.     */
  704.     if ((size_req + sizeof(_mem_ptr_hdr)) > (pool->pref_blk_size*7 >> 4)) {
  705.         blk_size = size_req + sizeof(_mem_ptr_hdr);
  706. #ifdef _PM_STATS
  707.         if (blk_size > pool->max_blk_size)
  708.             pool->max_blk_size = blk_size;
  709. #endif
  710.         }
  711.     else
  712.         blk_size = pool->pref_blk_size;
  713.     
  714.     blk_size = INT_ALIGN(blk_size, ALIGNMENT);
  715.     
  716. #ifdef _PM_STATS
  717.     pool->ave_blk_size = ( ( (pool->ave_blk_size * (float)pool->ave_blk_total) + (float)blk_size )
  718.                             / (float)(pool->ave_blk_total + 1) );
  719.     pool->ave_blk_total++;
  720. #endif
  721.  
  722.     new_blk = (_mem_blk_ptr) mNEWPTR(sizeof(_mem_blk));
  723.     if (new_blk == (_mem_blk_ptr)0)
  724.         return new_blk;
  725.     
  726.     /*
  727.     ** NOTE: We assume here that mNEWPTR() gives us proper alignment.
  728.     */
  729.     new_blk->memory = (char *) mNEWPTR(blk_size);
  730. #ifdef NEVER_DEFINED
  731.     if (new_blk->memory == (char *)0) {
  732.         /* Attempt to handle the request only. */
  733.         blk_size = size_req + sizeof(_mem_ptr_hdr);
  734.         blk_size = INT_ALIGN(blk_size, ALIGNMENT);
  735.         new_blk->memory = (char *) mNEWPTR(blk_size);
  736.         }
  737. #endif
  738.     
  739.     if (new_blk->memory == (char *)0) {
  740.         mDISPOSPTR((Ptr)new_blk);
  741.         DPRINTF(10, ("_pool_new_blk(pool:x%lx, size:%ld) Out of memory.\n", pool, size_req));
  742.         return (_mem_blk_ptr)0;
  743.         }
  744.     
  745. #ifdef _PM_STATS
  746.     pool->total_memory += sizeof(_mem_blk) + blk_size;
  747.     pool->total_storage += blk_size;
  748. #endif
  749.  
  750.     new_blk->pool = pool;
  751.     new_blk->size = blk_size;
  752.     new_blk->max_free = blk_size - sizeof(_mem_ptr_hdr);
  753.     
  754.     /* Add to the block list. */
  755.     new_blk->next = pool->blk_list;
  756.     pool->blk_list = new_blk;
  757.     
  758.     hdr = (_mem_ptr_hdr_ptr) new_blk->memory;
  759.     fastzero(hdr, sizeof(_mem_ptr_hdr));
  760.     
  761.     SET_PTR_FREE(hdr);
  762.     SET_PTR_SIZE(hdr, ( blk_size - sizeof(_mem_ptr_hdr) ) );
  763.     
  764.     DPRINTF(5, ("_pool_new_blk() new blk x%lx size %ld memory x%lx pool #%d [x%lx]\n",
  765.             new_blk, new_blk->size, new_blk->memory, pool->id, pool));
  766.     return new_blk;
  767.     }
  768.     
  769.  
  770. #ifdef DOCUMENTATION
  771.  
  772.     _pool_find_free_blk() looks for a block in the pool with enough free memory
  773.     to allocate the "size_req" bytes.
  774.     
  775. #endif
  776.  
  777. _mem_blk_ptr
  778. _pool_find_free_blk(pool, size_req, hdr_ptr)
  779. _mem_pool_ptr        pool;
  780. u_long                size_req;    /* size required */
  781. _mem_ptr_hdr_ptr    *hdr_ptr;
  782. {
  783. _mem_blk_ptr        blk, use_this_blk;
  784. _mem_ptr_hdr_ptr    loophdr, limit;
  785. long                hdrsize, max_size;
  786.  
  787. #ifdef _PM_DYNAMIC_MERGING
  788. _mem_ptr_hdr_ptr    lasthdr, nexthdr, blkhdr;
  789. long                lastsize, nextsize;
  790. #endif _PM_DYNAMIC_MERGING
  791.  
  792.     blk = pool->blk_list;
  793.     max_size = 0x3FFFFFFF;
  794.     for (use_this_blk=NULL; blk != (_mem_blk_ptr)0 ; blk=blk->next) {
  795.         if (blk->max_free >= size_req) {
  796.             if (use_this_blk == NULL) {
  797.                 use_this_blk = blk;
  798.                 max_size = blk->size;
  799.                 }
  800.             else if (blk->size < max_size) {
  801.                 use_this_blk = blk;
  802.                 max_size = blk->size;
  803.                 }
  804.             }
  805.         }
  806.     
  807.     blk = use_this_blk;
  808.     if (blk != NULL) {
  809.         loophdr = (_mem_ptr_hdr_ptr) blk->memory;
  810.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  811. #ifdef _PM_DYNAMIC_MERGING
  812.         lasthdr = (_mem_ptr_hdr_ptr)0;
  813. #endif _PM_DYNAMIC_MERGING
  814.         while (loophdr < limit) {
  815.             if (IS_PTR_FREE(loophdr)) {
  816.                 hdrsize = GET_PTR_SIZE(loophdr);
  817.                 if (hdrsize >= size_req) {
  818.                     DPRINTF(5, ("pool_find_free_blk() Found blk x%lx hdr x%lx pool #%d [x%lx]\n",
  819.                                 blk, loophdr, pool->id, pool));
  820.                     
  821.                     *hdr_ptr = loophdr;
  822.                     return blk;
  823.                     }
  824.  
  825. #ifdef _PM_DYNAMIC_MERGING
  826.                 else {
  827.                     nexthdr = (_mem_ptr_hdr_ptr)
  828.                                 ( (char *)loophdr + hdrsize + sizeof(_mem_ptr_hdr) );
  829.                     if (nexthdr < limit) {
  830.                         if (IS_PTR_FREE(nexthdr)) {
  831.                             nextsize = GET_PTR_SIZE(nexthdr);
  832.                             blk->max_free += sizeof(_mem_ptr_hdr);    /* We're gonna merge... */
  833.                             if ((nextsize + hdrsize + sizeof(_mem_ptr_hdr)) >= size_req) {
  834.                                 DPRINTF(3, ("pool_find_free_blk() F-Merge blk x%lx hdr1 x%lx hdr2 x%lx \n",
  835.                                             blk, loophdr, nexthdr));
  836.                                 
  837.                                 hdrsize = nextsize + hdrsize + sizeof(_mem_ptr_hdr);
  838.                                 SET_PTR_SIZE(loophdr, hdrsize);
  839.                                 *hdr_ptr = loophdr;
  840.                                 return blk;
  841.                                 }
  842.                             else {
  843.                                 /* OK, so merge anyways... */
  844.                                 hdrsize = nextsize + hdrsize + sizeof(_mem_ptr_hdr);
  845.                                 SET_PTR_SIZE(loophdr, hdrsize);
  846.                                 }
  847.                             }
  848.                         }
  849.                     if (lasthdr != (_mem_ptr_hdr_ptr)0) {
  850.                         if (IS_PTR_FREE(lasthdr)) {
  851.                             lastsize = GET_PTR_SIZE(lasthdr);
  852.                             blk->max_free += sizeof(_mem_ptr_hdr);    /* We're gonna merge... */
  853.                             if ((lastsize + hdrsize + sizeof(_mem_ptr_hdr)) >= size_req) {
  854.                                 DPRINTF(3, ("pool_find_free_blk() R-Merge blk x%lx hdr1 x%lx hdr2 x%lx \n",
  855.                                             blk, lasthdr, loophdr));
  856.                                 
  857.                                 hdrsize = lastsize + hdrsize + sizeof(_mem_ptr_hdr);
  858.                                 SET_PTR_SIZE(lasthdr, hdrsize);
  859.                                 *hdr_ptr = lasthdr;
  860.                                 return blk;
  861.                                 }
  862.                             else {
  863.                                 /* OK, so merge anyways... */
  864.                                 hdrsize = lastsize + hdrsize + sizeof(_mem_ptr_hdr);
  865.                                 SET_PTR_SIZE(lasthdr, hdrsize);
  866.                                 }
  867.                             loophdr = lasthdr;
  868.                             lasthdr = (_mem_ptr_hdr_ptr)0;
  869.                             }
  870.                         }
  871. #ifdef _PM_DYNAMIC_FREE
  872.                     blkhdr = (_mem_ptr_hdr_ptr)blk->memory;
  873.                     if (IS_PTR_FREE(blkhdr)) {
  874.                         if ((GET_PTR_SIZE(blkhdr) + sizeof(_mem_ptr_hdr)) == blk->size) {
  875.                             /* This blk is free-ed ... */
  876.                             
  877.                             _mem_blk_ptr    tmpblk, next;
  878.             
  879.                             if (blk == blk->pool->blk_list) {
  880.                                 blk->pool->blk_list = next = blk->next;
  881.                                 }
  882.                             else {
  883.                                 tmpblk = blk->pool->blk_list;
  884.                                 while (tmpblk != (_mem_blk_ptr)0) {
  885.                                     if (tmpblk->next == blk) {
  886.                                         tmpblk->next = next = blk->next;
  887.                                         break;
  888.                                         }
  889.                                     else
  890.                                         tmpblk = tmpblk->next;
  891.                                     }
  892.                                 if (tmpblk == (_mem_blk_ptr)0)
  893.                                     DPRINTF(1, ("pool_find_free_blk() ERROR: could not free blk x%lx from list!\n", blk));
  894.                                 }
  895.                             
  896.                             DPRINTF(3, ("pool_find_free_blk() Freeing Block x%lx from pool #%d!\n",
  897.                                         blk, blk->pool->id));
  898. #ifdef _PM_STATS
  899.                             pool->total_memory -= sizeof(_mem_blk) + blk->size;
  900.                             pool->total_storage -= blk->size;
  901. #endif
  902.                             mDISPOSPTR((Ptr)blk->memory);
  903.                             mDISPOSPTR((Ptr)blk);
  904.                             blk = next;
  905.                             break;    /* The while (hdr) loop, into while (blk) loop */
  906.                             }
  907.                         }    /* if (IS_PTR_FREE(blkhdr)) */
  908. #endif _PM_DYNAMIC_FREE
  909.  
  910.                     }
  911. #endif _PM_DYNAMIC_MERGING
  912.  
  913.                 }
  914. #ifdef _PM_DYNAMIC_MERGING
  915.             lasthdr = loophdr;
  916. #endif _PM_DYNAMIC_MERGING
  917.             loophdr = (_mem_ptr_hdr_ptr)
  918.                         ((char *)loophdr + GET_PTR_SIZE(loophdr) + sizeof(_mem_ptr_hdr));
  919.             }
  920.         }
  921.     
  922.     *hdr_ptr = (_mem_ptr_hdr_ptr)0;
  923.     return blk;
  924.     }
  925.     
  926.  
  927. #ifdef DOCUMENTATION
  928.  
  929.     _pool_find_ptr_blk() finds the block containing this pointer in "ptr".
  930.     
  931. #endif
  932.  
  933. _mem_bucket_ptr 
  934. _pool_find_ptr_bucket(ptr)
  935. char *                    ptr;
  936. {
  937. _mem_pool_ptr        pool;
  938. _mem_bucket_ptr    bucket;
  939.  
  940.     /*
  941.     ** Since the default list is stored at the front of the forest list,
  942.     ** we inherently search the default forest first. Nice.
  943.     */
  944.     pool = _mem_pool_forest;
  945.     
  946.     while (pool != (_mem_pool_ptr)0) {
  947.         if (bucket = pool->free_16)
  948.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size) {
  949.                 if (bucket->free_count+1 == bucket->max_count)
  950.                     pool->free_16 = nil;
  951.                 return bucket;
  952.             }
  953.         if (bucket = pool->free_32)
  954.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)    {
  955.                 if (bucket->free_count+1 == bucket->max_count)
  956.                     pool->free_32 = nil;
  957.                 return bucket;
  958.             }
  959.         if (bucket = pool->free_64)
  960.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size) {
  961.                 if (bucket->free_count+1 == bucket->max_count)
  962.                     pool->free_64 = nil;
  963.                 return bucket;
  964.             }
  965.         
  966.         for (bucket = pool->blk_16; bucket; bucket = bucket->next)
  967.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)
  968.                 return bucket;
  969.         for (bucket = pool->blk_32; bucket; bucket = bucket->next)
  970.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)
  971.                 return bucket;
  972.         for (bucket = pool->blk_64; bucket; bucket = bucket->next)
  973.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)
  974.                 return bucket;
  975.         
  976.         pool = pool->next;
  977.     }
  978.     
  979.     return (_mem_bucket_ptr)0;
  980. }
  981.  
  982. _mem_blk_ptr
  983. _pool_find_ptr_blk(ptr)
  984. char    *ptr;
  985. {
  986. _mem_pool_ptr    pool;
  987. _mem_blk_ptr    blk;
  988.  
  989.     /*
  990.     ** Since the default list is stored at the front of the forest list,
  991.     ** we inherently search the default forest first. Nice.
  992.     */
  993.     pool = _mem_pool_forest;
  994.     
  995.     while (pool != (_mem_pool_ptr)0) {
  996.         blk = pool->blk_list;
  997.         
  998.         while (blk != (_mem_blk_ptr)0) {
  999.             if ( ( ptr >= blk->memory ) &&
  1000.                  ( ptr <= ((char *)blk->memory + blk->size) ) )
  1001.                 return blk;
  1002.             else
  1003.                 blk = blk->next;
  1004.             }
  1005.         
  1006.         pool = pool->next;
  1007.         }
  1008.     
  1009.     return (_mem_blk_ptr)0;
  1010.     }
  1011.  
  1012.  
  1013. #ifdef DOCUMENTATION
  1014.  
  1015.     merge_free_list() runs the routine to merge and "release" any free-ed
  1016.     blocks back into the heap.
  1017.     
  1018. #endif
  1019.  
  1020. merge_free_list()
  1021. {
  1022.     return _pool_free_list_merge(_default_mem_pool);
  1023.     }
  1024.  
  1025.  
  1026. #ifdef DOCUMENTATION
  1027.  
  1028.     _pool_free_list_merge() will merge and "release" any free-ed blocks
  1029.     back into the heap.
  1030.     
  1031. #endif
  1032.  
  1033. _pool_free_list_merge(pool)
  1034. _mem_pool_ptr        pool;
  1035. {
  1036. _mem_blk_ptr        blk, nextblk;
  1037. _mem_ptr_hdr_ptr    loophdr, limit, nexthdr, blkhdr;
  1038. int                    result = 0;
  1039. long                hdrsize, nextsize;
  1040.  
  1041.     blk = pool->blk_list;
  1042.     while (blk != (_mem_blk_ptr)0) {
  1043.         loophdr = blkhdr = (_mem_ptr_hdr_ptr)blk->memory;
  1044.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1045.         while (loophdr < limit) {
  1046.             if (IS_PTR_FREE(loophdr)) {
  1047.                 hdrsize = GET_PTR_SIZE(loophdr);
  1048.                 nexthdr = (_mem_ptr_hdr_ptr)
  1049.                             ( (char *)loophdr + hdrsize + sizeof(_mem_ptr_hdr) );
  1050.                 /* Now loop and merge free ptr's til used one is hit... */
  1051.                 while (nexthdr < limit) {
  1052.                     if (IS_PTR_FREE(nexthdr)) {
  1053.                         nextsize = GET_PTR_SIZE(nexthdr);
  1054.                         blk->max_free += sizeof(_mem_ptr_hdr);    /* We're gonna merge... */
  1055.                         hdrsize = nextsize + hdrsize + sizeof(_mem_ptr_hdr);
  1056.                         SET_PTR_SIZE(loophdr, hdrsize);
  1057.                         nexthdr = (_mem_ptr_hdr_ptr)
  1058.                                     ( (char *)loophdr + hdrsize + sizeof(_mem_ptr_hdr) );
  1059.                         }
  1060.                     else
  1061.                         break;
  1062.                     }
  1063.                 }
  1064.             
  1065.             loophdr = (_mem_ptr_hdr_ptr)
  1066.                         ((char *)loophdr + GET_PTR_SIZE(loophdr) + sizeof(_mem_ptr_hdr));
  1067.             }
  1068.  
  1069.         /* Get next block now, so _PM_DYNAMIC_FREE can modify blk as desired */
  1070.         nextblk = blk->next;
  1071.  
  1072. #ifdef _PM_DYNAMIC_FREE
  1073.         if (IS_PTR_FREE(blkhdr)) {
  1074.             if ((GET_PTR_SIZE(blkhdr) + sizeof(_mem_ptr_hdr)) == blk->size) {
  1075.                 /* This blk is free-ed ... */
  1076.                 _mem_blk_ptr    tmpblk;
  1077.  
  1078.                 if (blk == blk->pool->blk_list) {
  1079.                     blk->pool->blk_list = blk->next;
  1080.                     }
  1081.                 else {
  1082.                     tmpblk = blk->pool->blk_list;
  1083.                     while (tmpblk != (_mem_blk_ptr)0) {
  1084.                         if (tmpblk->next == blk) {
  1085.                             tmpblk->next = blk->next;
  1086.                             break;
  1087.                             }
  1088.                         else
  1089.                             tmpblk = tmpblk->next;
  1090.                         }
  1091.                     if (tmpblk == (_mem_blk_ptr)0)
  1092.                         DPRINTF(1, ("pool_find_free_blk() ERROR: could not free blk x%lx from list!\n", blk));
  1093.                     }
  1094.                 
  1095.                 DPRINTF(3, ("pool_find_free_blk() Freeing Block x%lx from pool #%d!\n",
  1096.                             blk, blk->pool->id));
  1097. #ifdef _PM_STATS
  1098.                 pool->total_memory -= sizeof(_mem_blk) + blk->size;
  1099.                 pool->total_storage -= blk->size;
  1100. #endif
  1101.                 result += blk->size + sizeof(_mem_blk);
  1102.                 mDISPOSPTR((Ptr)blk->memory);
  1103.                 mDISPOSPTR((Ptr)blk);
  1104.                 }
  1105.             
  1106.             }    /* if (IS_PTR_FREE(blkhdr)) */
  1107. #endif _PM_DYNAMIC_FREE
  1108.         
  1109.         blk = nextblk;
  1110.         }
  1111.     
  1112.     return result;
  1113.     }
  1114.     
  1115.  
  1116. #ifdef DOCUMENTATION
  1117.  
  1118.     get_malloc_stats() return several statistics about the default heap.
  1119.     
  1120. #endif
  1121.  
  1122. get_malloc_stats(total_memory, total_free, total_malloc)
  1123. long        *total_memory;
  1124. long        *total_free;
  1125. long        *total_malloc;
  1126. {
  1127. _mem_pool_ptr        pool;
  1128. _mem_blk_ptr        blk;
  1129. _mem_ptr_hdr_ptr    hdr, limit;
  1130. u_long                total_size, used_space, free_space;
  1131. u_long                ptr_size;
  1132.  
  1133.     pool = _default_mem_pool;
  1134.     blk = pool->blk_list;
  1135.     total_size = used_space = free_space = 0;
  1136.     for ( ; blk != (_mem_blk_ptr)0; ) {
  1137.         hdr = (_mem_ptr_hdr_ptr) blk->memory;
  1138.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1139.         total_size += blk->size;
  1140.         for ( ; hdr && hdr < limit; ) {
  1141.             ptr_size = GET_PTR_SIZE(hdr);
  1142.             if (IS_PTR_FREE(hdr))
  1143.                 free_space += ptr_size;
  1144.             else
  1145.                 used_space += ptr_size;
  1146.             
  1147.             hdr = (_mem_ptr_hdr_ptr)
  1148.                     ( (char *)hdr + GET_PTR_SIZE(hdr) + sizeof(_mem_ptr_hdr) );
  1149.             }
  1150.         
  1151.         blk = blk->next;
  1152.         }
  1153.     
  1154.     *total_memory = total_size;
  1155.     *total_free = free_space;
  1156.     *total_malloc = used_space;
  1157.     }
  1158.  
  1159. #ifdef DEBUG
  1160.  
  1161. #include <stdio.h>
  1162.  
  1163. char    temp_str[512];
  1164.  
  1165. list_all_pool_stats(file)
  1166. FILE    *file;
  1167. {
  1168. _mem_pool_ptr        pool;
  1169.  
  1170.     pool = _mem_pool_forest;
  1171.     
  1172.     while (pool != (_mem_pool_ptr)0) {
  1173.         
  1174.         list_pool_stats(file, pool);
  1175.  
  1176.         pool = pool->next;
  1177.         }
  1178.     
  1179.     }
  1180.  
  1181.  
  1182. list_pool_stats(file, pool)
  1183. FILE    *file;
  1184. _mem_pool_ptr        pool;
  1185. {
  1186. _mem_blk_ptr        blk;
  1187. _mem_ptr_hdr_ptr    hdr, limit;
  1188. int                    i, j;
  1189. int                    num_used_hdrs, num_free_hdrs;
  1190. u_long                used_hdr_space, free_hdr_space;
  1191. u_long                ptr_size, max_free_size, max_used_size;
  1192. float                ave_used_size, ave_free_size, frag_ratio;
  1193.  
  1194.     if (file == (FILE *)0) {
  1195.         file = stdout;
  1196.         }
  1197.     
  1198.     fprintf(file, "POOL STATISTICS FOR ID#%d @ x%lx blk_list x%lx pref_blk_size %ld\n",
  1199.             pool->id, pool, pool->blk_list, pool->pref_blk_size);
  1200.  
  1201. #ifdef _PM_STATS
  1202.     fprintf(file, "\tMEMORY: Total memory %ld Total ptr space %ld Currently malloc-ed %ld\n",
  1203.             pool->total_memory, pool->total_storage, pool->total_malloc);
  1204.     fprintf(file, "\tREQUESTS: Ave req size %f Total reqs %ld Total size reqs %f\n",
  1205.             pool->ave_req_size, pool->ave_req_total, 
  1206.             (float) (pool->ave_req_size * (float)pool->ave_req_total));
  1207.     fprintf(file, "\tBLOCKS: Max block size %ld Ave block size %f\n",
  1208.             pool->max_blk_size, pool->ave_blk_size);
  1209.     fprintf(file, "\tBLOCKS: Total ave blocks %ld Total ave size %f\n",
  1210.             pool->ave_blk_total,(float) (pool->ave_blk_size * (float)pool->ave_blk_total));
  1211. #endif
  1212.  
  1213.         fprintf(file, "POOL BLOCK STATISTICS:\n");
  1214.         
  1215.         blk = pool->blk_list;
  1216.         for (i=0; blk != (_mem_blk_ptr)0; i++) {
  1217.             hdr = (_mem_ptr_hdr_ptr) blk->memory;
  1218.             limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1219.             num_used_hdrs = num_free_hdrs = 0;
  1220.             used_hdr_space = free_hdr_space = 0;
  1221.             max_free_size = max_used_size = 0;
  1222.             for (j=0; hdr && hdr < limit; j++) {
  1223.                 ptr_size = GET_PTR_SIZE(hdr);
  1224.                 if (IS_PTR_FREE(hdr)) {
  1225.                     num_free_hdrs++;
  1226.                     free_hdr_space += ptr_size;
  1227.                     if (ptr_size > max_free_size)
  1228.                         max_free_size = ptr_size;
  1229.                     }
  1230.                 else {
  1231.                     num_used_hdrs++;
  1232.                     used_hdr_space += ptr_size;
  1233.                     if (ptr_size > max_used_size)
  1234.                         max_used_size = ptr_size;
  1235.                     }
  1236.                 
  1237.                 hdr = (_mem_ptr_hdr_ptr)
  1238.                         ( (char *)hdr + GET_PTR_SIZE(hdr) + sizeof(_mem_ptr_hdr) );
  1239.                 }
  1240.             
  1241.             if (num_free_hdrs == 0)
  1242.                 ave_free_size = (float)0.0;
  1243.             else
  1244.                 ave_free_size = (float)free_hdr_space / (float)num_free_hdrs;
  1245.             
  1246.             if (num_used_hdrs == 0)
  1247.                 ave_used_size = (float)0.0;
  1248.             else
  1249.                 ave_used_size = (float)used_hdr_space / (float)num_used_hdrs;
  1250.             
  1251.             if (num_used_hdrs == 0) {
  1252.                 frag_ratio = (float)num_free_hdrs / 2.0;
  1253.                 }
  1254.             else {
  1255.                 frag_ratio = (float)num_free_hdrs / (float)num_used_hdrs;
  1256.                 }
  1257.             
  1258.             fprintf(file, "\tBLOCK #%-4d Fragmentation Ratio %5.2f\n", i, frag_ratio);
  1259.             fprintf(file, "\t      #%-4d    Block Size %ld Ptr x%lx MaxFree %ld\n",
  1260.                     i, blk->size, blk->memory, blk->max_free);
  1261.             fprintf(file, "\t      #%-4d    Number free ptrs %d Number used ptrs %d\n",
  1262.                     i, num_free_hdrs, num_used_hdrs);
  1263.             fprintf(file, "\t      #%-4d    Free space %ld Used space %ld\n",
  1264.                     i, free_hdr_space, used_hdr_space);
  1265.             fprintf(file, "\t      #%-4d    Max free ptr %ld Max used ptr %ld\n",
  1266.                     i, max_free_size, max_used_size);
  1267.             fprintf(file, "\t      #%-4d    Ave free ptr size %5.1f Ave used ptr size %5.1f\n",
  1268.                     i, ave_free_size, ave_used_size);
  1269.  
  1270.             blk = blk->next;
  1271.             }
  1272.     }
  1273.  
  1274.  
  1275. list_pool_forest(file, with_data)
  1276. FILE    *file;
  1277. int        with_data;
  1278. {
  1279. _mem_pool_ptr        pool;
  1280. _mem_blk_ptr        blk;
  1281. _mem_ptr_hdr_ptr    hdr, limit;
  1282. int                    i, j;
  1283. extern char            temp_str[];
  1284.  
  1285.     if (file == (FILE *)0) {
  1286.         file = stdout;
  1287.         }
  1288.     
  1289.     pool = _mem_pool_forest;
  1290.     while (pool != (_mem_pool_ptr)0) {
  1291.         
  1292.         list_pool_stats(file, pool);
  1293.         
  1294.         blk = pool->blk_list;
  1295.         for (i=0; blk != (_mem_blk_ptr)0; i++) {
  1296.             fprintf(file, "   BLK #%05d ; @ x%lx ; blk_size %ld ; memory x%lx ; max_free %ld\n",
  1297.                     i, blk, blk->size, blk->memory, blk->max_free);
  1298.             fprintf(file, "   BLK          pool x%lx ; next blk x%lx\n", blk->pool, blk->next);
  1299.             
  1300.             hdr = (_mem_ptr_hdr_ptr) blk->memory;
  1301.             limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1302.             for (j=0; hdr && hdr < limit; j++) {
  1303.                 sprintf(temp_str, "      PTR #%d ; hdr x%lx ; nxt x%08lx ; size %ld ; flgs x%02x",
  1304.                         j, hdr, hdr->size, GET_PTR_SIZE(hdr), GET_PTR_FLAGS(hdr));
  1305.                 if (with_data)
  1306.                     hex_dump(file, temp_str,
  1307.                             (char *)((char *)hdr + sizeof(_mem_ptr_hdr)),
  1308.                             GET_PTR_SIZE(hdr));
  1309.                 else
  1310.                     fprintf(file, "%s\n", temp_str);
  1311.                 
  1312.                 hdr = (_mem_ptr_hdr_ptr)
  1313.                         ( (char *)hdr + GET_PTR_SIZE(hdr) + sizeof(_mem_ptr_hdr) );
  1314.                 }
  1315.             
  1316.             blk = blk->next;
  1317.             }
  1318.         
  1319.         pool = pool->next;
  1320.         }
  1321.     }
  1322.  
  1323. #define ROW_BYTES        16
  1324.  
  1325. hex_dump(output, title, ptr, bytes)
  1326. FILE    *output;
  1327. char    *title;
  1328. char    *ptr;
  1329. long    bytes;
  1330. {
  1331. int                rows, residue, i, j;
  1332. unsigned char    save_buf[ROW_BYTES+2];
  1333. unsigned char    hex_buf[4];
  1334. char            hex_chars[20];
  1335.     strcpy(hex_chars, "0123456789ABCDEF");
  1336.     
  1337.     fprintf(output, "\n%s - x%lX (%ld) bytes.\n", title, bytes, bytes);
  1338.     rows = bytes >> 4;
  1339.     residue = bytes & 0x0000000F;
  1340.     for (i=0; i<rows; i++) {
  1341.         fprintf(output, "%04.4X:", i * ROW_BYTES);
  1342.         for (j=0; j<ROW_BYTES; j++) {
  1343.             save_buf[j] = *ptr++;
  1344.             hex_buf[0] = hex_chars[(save_buf[j] >> 4) & 0x0F];
  1345.             hex_buf[1] = hex_chars[save_buf[j] & 0x0F];
  1346.             hex_buf[2] = '\0';
  1347.             fprintf(output, " %2.2s", hex_buf);
  1348.             if (save_buf[j] < 0x20 || save_buf[j] > 0xD9) save_buf[j] = '.';
  1349.             }
  1350.         save_buf[ROW_BYTES+1] = '\0';
  1351.         fprintf(output, "\t/* %16.16s */\n", save_buf);
  1352.         }
  1353.     if (residue) {
  1354.         fprintf(output, "%04.4X:", i * ROW_BYTES);
  1355.         for (j=0; j<residue; j++) {
  1356.             save_buf[j] = *ptr++;
  1357.             hex_buf[0] = hex_chars[(save_buf[j] >> 4) & 0x0F];
  1358.             hex_buf[1] = hex_chars[save_buf[j] & 0x0F];
  1359.             hex_buf[2] = '\0';
  1360.             fprintf(output, " %2.2s", hex_buf);
  1361.             if (save_buf[j] < 0x20 || save_buf[j] > 0xD9) save_buf[j] = '.';
  1362.             }
  1363.         for (/*j INHERITED*/; j<ROW_BYTES; j++) {
  1364.             save_buf[j] = ' ';
  1365.             fprintf(output, "   ");
  1366.             }
  1367.         save_buf[ROW_BYTES+1] = '\0';
  1368.         fprintf(output, "\t/* %16.16s */\n", save_buf);
  1369.         }
  1370.     }
  1371.  
  1372. #ifdef TESTING
  1373.  
  1374. main(argc, argv)
  1375. char    *argc;
  1376. char    *argv[];
  1377. {
  1378. int        i;
  1379. _mem_pool_ptr pool;
  1380. char    *ptr, *aptr[20];
  1381. char    input[128];
  1382. #pragma unused (argc, argv)
  1383.  
  1384.     printf("Debug level?\n");
  1385.     gets(input);
  1386.     if (input[0] == '\0' || input[0] == 'q')
  1387.         return 0;
  1388.     
  1389.     pool_malloc_debug_level = atoi(input);
  1390.     printf("Debug level set to %d\n", pool_malloc_debug_level);
  1391.     
  1392.     fprintf(stderr, "******************** START ********************\n");
  1393.     list_pool_forest(stderr, 0);
  1394.     
  1395.     printf("Allocating in default (system) pool...\n");
  1396.     for (i = 10 ; i < (10 * 1024) ; i += 128)
  1397.         if (malloc(i) == NULL)
  1398.             break;
  1399.     
  1400.     fprintf(stderr, "******************** ## 1 ## ********************\n");
  1401.     list_pool_forest(stderr, 0);
  1402.     
  1403.     printf("Allocating and Free-ing in default (system) pool...\n");
  1404.     for (i = 10 ; i < (10 * 1024) ; i += 128)
  1405.         if ((ptr = malloc(i)) != NULL)
  1406.             free(ptr);
  1407.         else
  1408.             break;
  1409.         
  1410.     fprintf(stderr, "******************** ## 2 ## ********************\n");
  1411.     list_pool_forest(stderr, 0);
  1412.     
  1413.     printf("Allocating and Free-ing again in default (system) pool...\n");
  1414.     for (i = 0 ; i < 20 ; i++)
  1415.         aptr[i] = NULL;
  1416.     for (i = 0 ; i < 20 ; i++) {
  1417.         aptr[i] = malloc(i * 128);
  1418.         if (aptr[i] == NULL)
  1419.             break;
  1420.         }
  1421.     for (i = 19 ; i >= 0 ; i--)
  1422.         if (aptr[i] != NULL) {
  1423.             free(aptr[i]);
  1424.             }
  1425.         
  1426.     fprintf(stderr, "******************** ## 3 ## ********************\n");
  1427.     list_pool_forest(stderr, 0);
  1428.     
  1429.     pool = new_malloc_pool ( 2001, (16 * 1024) );
  1430.     printf("new_malloc_pool ( 2001, %d ) returns x%lx\n", (16 * 1024), pool);
  1431.     if (pool) {
  1432.         set_default_pool ( 2001 );
  1433.         
  1434.         printf("Allocating in pool #2001...\n");
  1435.         for (i = 10 ; i < (10 * 1024) ; i += 128)
  1436.             if (malloc(i) == NULL)
  1437.                 break;
  1438.         }
  1439.  
  1440.     fprintf(stderr, "******************** ## 4 ## ********************\n");
  1441.     list_pool_forest(stderr, 0);
  1442.     
  1443.     printf("Free-ing memory in pool #2001...\n");
  1444.     free_pool_memory ( 2001 );
  1445.  
  1446.     fprintf(stderr, "******************** ## 5 ## ********************\n");
  1447.     list_pool_forest(stderr, 0);
  1448.     
  1449.     printf("Done.\n");
  1450.     }
  1451.  
  1452. #endif TESTING
  1453.  
  1454. #endif _PM_STATS
  1455.